package com.yzl.frelink.entities.component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.yzl.frelink.entities.chart.Function;
import com.yzl.frelink.entities.chart.Parameter;
import com.yzl.frelink.entities.chart.StateTree;
import com.yzl.frelink.entities.chart.StateTreeNode;
import com.yzl.frelink.entities.chart.Transition;

import lombok.Data;

@Data
public class Chart extends Component {
    private StateTree stateTree;
    private Map<String, StateTreeNode> states;
    private List<Transition> transitions;
    private List<Parameter> parameters;
    private List<Function> functions;
    
    private List<String> statesCompilingOrder;
    private List<String> inputPortOrder;
    private List<String> outputPortOrder;

    @Override
    public String getType() {
        return "Chart";
    }

    public Chart(String name) {
        super(name);
        this.states = new HashMap<>();
        this.transitions = new ArrayList<>();
        this.parameters = new ArrayList<>();
        this.functions = new ArrayList<>();
    }

    public void addState(StateTreeNode node) {
        this.states.put(node.getName(), node);
    }

    public void removeState(String name) {
        this.states.remove(name);
    }

    public StateTreeNode getState(String name) {
        return this.states.get(name);
    }

    public void addTransition(Transition transition) {
        this.transitions.add(transition);
    }

    public void removeTransition(StateTreeNode from, StateTreeNode to) {
        this.transitions.removeIf(transition -> transition.getFrom() == from && transition.getTo() == to);
    }

    public void addParameter(Parameter parameter) {
        parameter.setMaster(this.getName());
        this.parameters.add(parameter);
    }

    public void setValidStatesCompilingOrder() {
        this.statesCompilingOrder = new ArrayList<>();
        for (StateTreeNode node : this.states.values()) {
            if (node.getType() != 1) { // Exclude junctions
                this.statesCompilingOrder.add(node.getName());
            }
        }
    }

    public String getExitStateGuard(StateTreeNode state) {
        List<Transition> inTrans = new ArrayList<>();
        for (Transition transition : this.transitions) {
            if (transition.getTo() == state && !state.hasChild(transition.getFrom())) {
                inTrans.add(transition);
            }
        }
        List<String> guards = new ArrayList<>();
        for (Transition transition : inTrans) {
            String antiGuard = transition.getAntiGuard();
            if (antiGuard != null && !antiGuard.isEmpty()) {
                guards.add(antiGuard);
        }
        }
        return String.join(" && ", guards);
    }

    public void setPortOrder() {
        if (this.parameters == null || this.parameters.isEmpty()) {
            System.out.println("No parameters found in chart: " + this.getName());
            return;
        }
        this.inputPortOrder = new ArrayList<>();
        this.outputPortOrder = new ArrayList<>();
        for (Parameter param : this.parameters) {
            if (param.getScopeStr().equals("Input")) {
                this.inputPortOrder.add(param.getName());
            } else {
                this.outputPortOrder.add(param.getName());
            }
        }
        System.out.println("Parameter order set for chart: " + this.getName());
    }

    public int getOutputPortIndex(String name) {
        return this.outputPortOrder.indexOf(name) + 1;
    }

    public int getInputPortIndex(String name) {
        return this.inputPortOrder.indexOf(name) + 1;
    }

    public Parameter getParameterByName(String name) {
        for (Parameter param : this.parameters) {
            if (param.getName().equals(name)) {
                return param;
            }
        }
        return null;
    }
}
